package org.piggy.common.rule;

import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

public class Rule implements Comparable<Rule>, Serializable {

    /**
     * 规则ID，全局唯一
     */
    private String id;
    private String serviceName;
    private String protocol;
    private String prefix;
    private List<String> paths;
    private Integer order;
    private Integer timeout = 1000;
    private boolean whenComplete = true;
    private Set<FilterConfig> filterConfigs;
    private FlowControlConfig flowControlConfig;
    private LoadBalanceConfig loadBalanceConfig;
    private CircuitBreakerConfig circuitBreakerConfig;

    public Integer getTimeout() {
        return timeout;
    }

    public void setTimeout(Integer timeout) {
        this.timeout = timeout;
    }

    public boolean getWhenComplete() {
        return whenComplete;
    }

    public void setWhenComplete(boolean whenComplete) {
        this.whenComplete = whenComplete;
    }

    public CircuitBreakerConfig getCircuitBreakerConfig() {
        return circuitBreakerConfig;
    }

    public void setCircuitBreakerConfig(CircuitBreakerConfig circuitBreakerConfig) {
        this.circuitBreakerConfig = circuitBreakerConfig;
    }

    public LoadBalanceConfig getLoadBalanceConfig() {
        return loadBalanceConfig;
    }

    public void setLoadBalanceConfig(LoadBalanceConfig loadBalanceConfig) {
        this.loadBalanceConfig = loadBalanceConfig;
    }

    public FlowControlConfig getFlowControlConfig() {
        return flowControlConfig;
    }

    public void setFlowControlConfig(FlowControlConfig flowControlConfig) {
        this.flowControlConfig = flowControlConfig;
    }

    @Override
    public int compareTo(Rule that) {
        int orderCompare = Integer.compare(this.order, that.getOrder());
        if(orderCompare == 0){
            return this.id.compareTo(that.getId());
        }
        return orderCompare;
    }

    public static class FlowControlConfig {
        private Integer count;

        public Integer getCount() {
            return count;
        }

        public void setCount(Integer count) {
            this.count = count;
        }
    }

    public static class CircuitBreakerConfig{
        private Integer count;

        private Integer timeWindow = 60;

        private Double slowRatioThreshold = 0.6;

        private Integer minRequestAmount = 50;

        private Integer statIntervalMs = 60000;

        public Integer getTimeWindow() {
            return timeWindow;
        }

        public void setTimeWindow(Integer timeWindow) {
            this.timeWindow = timeWindow;
        }

        public Double getSlowRatioThreshold() {
            return slowRatioThreshold;
        }

        public void setSlowRatioThreshold(Double slowRatioThreshold) {
            this.slowRatioThreshold = slowRatioThreshold;
        }

        public Integer getMinRequestAmount() {
            return minRequestAmount;
        }

        public void setMinRequestAmount(Integer minRequestAmount) {
            this.minRequestAmount = minRequestAmount;
        }

        public Integer getStatIntervalMs() {
            return statIntervalMs;
        }

        public void setStatIntervalMs(Integer statIntervalMs) {
            this.statIntervalMs = statIntervalMs;
        }

        public Integer getCount() {
            return count;
        }

        public void setCount(Integer count) {
            this.count = count;
        }
    }

    public static class FilterConfig {
        private String id;
        private String config;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getConfig() {
            return config;
        }

        public void setConfig(String config) {
            this.config = config;
        }

        @Override
        public boolean equals(Object o){
            if (this == o)
                return true;

            if((o == null) || getClass() != o.getClass()){
                return false;
            }

            FilterConfig that = (FilterConfig) o;
            return this.id.equals(that.id);
        }

        @Override
        public int hashCode(){
            return Objects.hash(id);
        }
    }

    public static class LoadBalanceConfig {
        private String type;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }

    public Rule(){}

    public Rule(String id, String protocol, String prefix, List<String> paths,
                Integer order, Set<FilterConfig> filterConfigs, FlowControlConfig flowControlConfig) {
        this.id = id;
        this.protocol = protocol;
        this.prefix = prefix;
        this.paths = paths;
        this.order = order;
        this.filterConfigs = filterConfigs;
        this.flowControlConfig = flowControlConfig;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public List<String> getPaths() {
        return paths;
    }

    public void setPaths(List<String> paths) {
        this.paths = paths;
    }

    public Integer getOrder() {
        return order;
    }

    public void setOrder(Integer order) {
        this.order = order;
    }

    public Set<FilterConfig> getFilterConfigs() {
        return filterConfigs;
    }

    public void setFilterConfigs(Set<FilterConfig> filterConfigs) {
        this.filterConfigs = filterConfigs;
    }

    @Override
    public boolean equals(Object o){
        if (this == o)
            return true;

        if((o == null) || getClass() != o.getClass()){
            return false;
        }

        Rule that = (Rule) o;
        return id.equals(that.id);
    }

    @Override
    public int hashCode(){
        return Objects.hash(id);
    }

    public FilterConfig getFilterConfig(String id){
        for(FilterConfig config : filterConfigs){
            if(config.getId().equals(id)){
                return config;
            }
        }
        return null;
    }

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }
}
